package com.dxy.gateway.auth;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.dxy.common.exp.ServiceException;
import com.dxy.common.utils.JwtUtil;
import com.dxy.common.vo.Result;
import com.dxy.gateway.provider.AuthServiceProvider;
import com.dxy.gateway.service.PermissionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 认证校验全局过滤器
 */
@Slf4j
@Component
public class AuthGlobalFilter implements GlobalFilter {

    @Autowired
    private GatewayAuthProperties gatewayAuthProperties;
    @Autowired
    private PermissionService permissionService;

    private PathMatcher pathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getURI().getPath();
        log.info("[网关AuthGlobalFilter]url: {}", url);
        List<String> excludeUrls = this.gatewayAuthProperties.getExcludeUrls();
        if (CollUtil.isNotEmpty(excludeUrls)) {
            boolean skip = false;
            for (String excludeUrl : excludeUrls) {
                if (pathMatcher.match(excludeUrl, url)) {
                    skip = true;
                    break;
                }
            }
            if (skip) {
                return chain.filter(exchange);// 排除路径不校验token
            }
        }

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String token = request.getHeaders().getFirst(JwtUtil.TOKEN_NAME);
        // token校验失败时，网关直接进行响应，请求不会转发给目标微服务
        if (StringUtils.isBlank(token)) {
            return writeReponse(response, Result.fail("token not found！"));
        }

        try {
            if (JwtUtil.verifyToken(token)) {// 校验token
                // 调用认证服务检查权限
                if (permissionService.checkPermission(token, url)) {

                    // 将jwt传给服务
                    ServerHttpRequest.Builder builder = request.mutate();
                    builder.header(JwtUtil.TOKEN_NAME, token);
                    return chain.filter(exchange.mutate().request(builder.build()).build());
                } else {
                    return writeReponse(response, Result.fail(401, "no permission！"));
                }

            } else {
                return writeReponse(response, Result.fail("token check fail！"));
            }
        } catch (ServiceException e) {
            log.error("[网关AuthGlobalFilter]token校验异常:{}", e.getMessage());
            return writeReponse(response, Result.fail(e));
        }
    }

    private Mono<Void> writeReponse(ServerHttpResponse response, Result result) {
        DataBuffer buffer = response.bufferFactory().wrap(JSONUtil.toJsonStr(result).getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Flux.just(buffer));// 异步响应数据
    }

}
